home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Nebula 2
/
Nebula Two.iso
/
NextAnswers
/
UniqueKey_oracle
/
UniqueKey.m
< prev
next >
Wrap
Text File
|
1994-06-14
|
7KB
|
210 lines
#import <appkit/appkit.h>
#import "UniqueKey.h"
static BOOL _Debug = YES;
static id _connectionDictionary = nil;
@implementation UniqueKey
/******************************************************************************
* Allow the programmer to specify login information for our separate UniqueKey
* channel. If no information is supplied, we display our own login panel.
******************************************************************************/
+ setConnectionDictionary:(NSDictionary *)connectionDictionary
{
if(_connectionDictionary) [_connectionDictionary autorelease];
_connectionDictionary = [connectionDictionary retain];
return self;
}
+ connectionDictionary
{
return [[_connectionDictionary retain] autorelease];
}
/******************************************************************************
* The UniqueKey objects share a database channel that is sure
* to be free to allow immediate reservation of a block of keys.
******************************************************************************/
- initSharedChannel
{
NSString *modelName = @"UniqueKey";
NSString *path;
NSString *_entityName = @"UniqueKey";
EOModel *eoModel;
EOAdaptor *eoAdaptor;
EODatabase *db;
static EODatabaseContext *_sharedContext;
static EODatabaseChannel *_sharedChannel;
static EOEntity *_sharedEntity;
static BOOL initFlag = NO;
if(!initFlag) {
path = [EOModel findPathForModelNamed:modelName];
if(!path) {
NXRunAlertPanel([NXApp appName],
"UniqueKey is unable to find %s",NULL,NULL,NULL,[modelName cString]);
return nil;
}
eoModel=[[EOModel alloc] initWithContentsOfFile:path];
if(!eoModel) {
NXRunAlertPanel([NXApp appName],
"UniqueKey is unable to open %s",NULL,NULL,NULL,[path cString]);
return nil;
}
eoAdaptor=[[EOAdaptor adaptorWithModel:eoModel] retain];
if(!eoAdaptor) {
NXRunAlertPanel([NXApp appName],
"UniqueKey is unable to create adaptorWithModel:",NULL,NULL,NULL);
return nil;
}
if([UniqueKey connectionDictionary]!=nil)
[eoAdaptor setConnectionDictionary:[UniqueKey connectionDictionary]];
if(![eoAdaptor hasValidConnectionDictionary])
[eoAdaptor runLoginPanelAndValidateConnectionDictionary];
db=[[EODatabase alloc] initWithAdaptor:eoAdaptor];
if(!db) {
NXRunAlertPanel([NXApp appName],
"UniqueKey is unable to initWithAdaptor:",NULL,NULL,NULL);
return nil;
}
_sharedContext=[[EODatabaseContext alloc] initWithDatabase:db];
if(!_sharedContext) {
NXRunAlertPanel([NXApp appName],
"UniqueKey is unable to initWithDatabase:",NULL,NULL,NULL);
return nil;
}
_sharedChannel=[[EODatabaseChannel alloc] initWithDatabaseContext:_sharedContext];
if(!_sharedChannel) {
NXRunAlertPanel([NXApp appName],
"UniqueKey is unable to initWithDatabaseContext:",NULL,NULL,NULL);
return nil;
}
_sharedEntity=[[eoModel entityNamed:_entityName] retain];
if(!_sharedEntity) {
NXRunAlertPanel([NXApp appName],
"UniqueKey is unable to find entityNamed:%s",NULL,NULL,NULL,[_entityName cString]);
return nil;
}
[[_sharedChannel adaptorChannel] openChannel];
if(_Debug) [[_sharedChannel adaptorChannel] setDelegate:self];
initFlag=TRUE;
}
dbContext = [_sharedContext retain];
dbChannel = [_sharedChannel retain];
uniqueKeyEntity = [_sharedEntity retain];
return self;
}
/******************************************************************************
* Init a UniqueKey object to reserve integer keys in blocks of <count> keys. Hold
* off reserving any keys until the first call to nextKey. Each call to nextKey
* returns a unique integer key. The first call reserves a block of <count> keys.
* When the block has been used, a new block is reserved.
*
* UniqueKey uses a separate table to hold the external entity name and current
* max reserved integer key. The UniqueKey objects share a database channel that
* is sure to be free to allow immediate reservation of a block of keys.
******************************************************************************/
- initWithEntity:(EOEntity*)entity count:(unsigned int)count
{
NSString *qualifierString;
EOQualifier *tableNameQualifier;
NSNumber *max;
keyCount = count;
nextKey = 0;
maxKey = 0;
if(!entity || ![self initSharedChannel]) return nil;
// Construct the qualifier for our name
qualifierString = [NSString stringWithFormat:@"EntityName = '%@'",[entity externalName]];
tableNameQualifier = [[[EOQualifier allocWithZone:[self zone]]
initWithEntity:uniqueKeyEntity qualifierFormat:qualifierString] autorelease];
// Select the object and check for the presence of our name and "MaxKey"
[dbContext beginTransaction];
[dbChannel selectObjectsDescribedByQualifier:tableNameQualifier fetchOrder:nil];
tableMax=[[dbChannel fetchWithZone:[dbChannel zone]] retain];
[dbChannel cancelFetch];
[dbContext commitTransaction];
// Was there an entry for our table name?
if(!tableMax) {
NSLog(@"Unique key was unable to fetch EntityName = %@",[entity externalName]);
return nil;
}
// Then there should be a value for "MaxKey" for our table
max=[tableMax objectForKey:@"MaxKey"];
if(!max) {
NSLog(@"Unique key method nextKey could not fine MaxKey");
return nil;
}
return self;
}
/******************************************************************************
* Hand out the next unique key from our reserved block. If the block is exhausted,
* increment the max_id (high-water mark) and attempt to updateObject:. This
* writes the new max_id back to the table. Under optimistic locking (the default)
* the update will fail if another client has bumped up the max_id since our last use.
* In that case, we need to refetchObject: and try again.
******************************************************************************/
- (int) nextKey
{
NSNumber *max;
// Hand out our next reserved key. If we are out of keys, fall through to
// reserve another block of keyCount keys.
if(++nextKey<=maxKey) return nextKey;
// Attempt to bump up the count by keyCount. Fail on optomistic lock if someone
// else reserved a chunck since our original select (or our last update).
[dbContext beginTransaction];
while(1) {
max = [tableMax objectForKey:@"MaxKey"];
maxKey = [max intValue]+keyCount;
[tableMax setObject:[NSNumber numberWithInt:maxKey] forKey:@"MaxKey"];
if([dbChannel updateObject:tableMax]) break;
[dbContext rollbackTransaction];
[dbContext beginTransaction];
[dbChannel refetchObject:tableMax];
}
[dbContext commitTransaction];
nextKey=maxKey-keyCount+1;
return nextKey;
}
/******************************************************************************
* Echo SQL when debug is enabled.
******************************************************************************/
- (EODelegateResponse)adaptorChannel:channel
willEvaluateExpression:(NSMutableString *)expression
{
NSLog(expression);
return EODelegateApproves;
}
@end